package cn.lili.modules.promotion.serviceimpl;

import cn.lili.common.vo.PageVO;
import cn.lili.modules.promotion.entity.dos.Advertising;
import cn.lili.modules.promotion.entity.dos.AdvertisingSpace;
import cn.lili.modules.promotion.entity.enums.AdvertisingRevealFrequencyEnum;
import cn.lili.modules.promotion.mapper.AdvertisingMapper;
import cn.lili.modules.promotion.mapper.AdvertisingSpaceMapper;
import cn.lili.modules.promotion.service.AdvertisingService;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author:xiangqian
 * @date: 2024/4/17 9:18
 */
@Service
@Slf4j
public class AdvertisingSerivceImpl extends ServiceImpl<AdvertisingMapper, Advertising> implements AdvertisingService {

    @Resource
    private AdvertisingSpaceMapper advertisingSpaceMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 分页查询贡献值明细
     *
     * @param advertising 查询条件{@link Advertising}
     * @param page        分页条件{@link PageVO}
     * @return 分页返回结果
     */
    @Override
    public Page<Advertising> page(Advertising advertising, PageVO page) {
        return this.baseMapper.selectPage(PageUtil.initPage(page), advertising.queryWrapperPage());
    }

    /**
     * 立即失效
     *
     * @param id 广告ID
     * @return 是否成功
     */
    @Override
    public Boolean updateByIdStatus(String id) {
        //1.判空
        Assert.notNull(id, "广告ID不能为空");
        //2.更新
        Advertising advertising = new Advertising();
        advertising.setId(id);
        advertising.setStatus("2");
        return this.updateById(advertising);
    }

    /**
     * 查询最新广告
     *
     * @param openId     飞语openId，有就传，没有就不穿，用于控制每日弹框次数
     * @param spaceIndex 广告位标识，用于指定广告位
     * @return 是否成功
     */
    @Override
    public List<Advertising> queryNew(String openId, String spaceIndex) {
        //1.判空
        Assert.notNull(spaceIndex, "广告位标识，用于指定广告位,不能为空");
        Assert.notNull(openId, "openId不能为空");

        //2.查询广告位
        AdvertisingSpace dbAdvertisingSpace = advertisingSpaceMapper.getByIndex(spaceIndex);
        Assert.notNull(dbAdvertisingSpace, "广告位不存在!");
        Assert.isTrue(!"1".equals(dbAdvertisingSpace.getStatus()), "广告位已关闭!");

        //3.失效广告
        this.baseMapper.updateByEffectiveTimeEnd();

        //4.根据广告位查询广告
        List<Advertising> advertisings = this.baseMapper.selectBySpaceId(dbAdvertisingSpace.getId());

        //5.根据频率排除广告
        List<Advertising> resultlList = new ArrayList<>();
        for (Advertising advertising : advertisings) {
            if (AdvertisingRevealFrequencyEnum.ONCE.name().equals(advertising.getRevealFrequency())) {
                //每日一次
                String key = spaceIndex + "_" + advertising.getId() + "_" + openId;
                if (stringRedisTemplate.opsForValue().get(key) == null) {
                    resultlList.add(advertising);
                    stringRedisTemplate.opsForValue().set(key, "1", getByExpirationSeconds(), TimeUnit.SECONDS);
                }
            } else {
                //无限制
                resultlList.add(advertising);
            }
        }

        return resultlList;
    }

    /**
     * 获取间隔时间
     */
    public long getByExpirationSeconds() {
        // 获取当天的日期和当天的最后一秒时间
        LocalDate currentDate = LocalDate.now();
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);

        // 计算距离当天最后一秒的时间间隔（秒数）
        long expirationSeconds = LocalDateTime.now().until(endOfDay, java.time.temporal.ChronoUnit.SECONDS);
        return expirationSeconds;
    }
}
